﻿//
// <copyright file="ApplicationEnvironment.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
using System;
using Microsoft.ServiceHosting.ServiceRuntime;
using System.Configuration;
using System.Web.Configuration;
using System.IO;


namespace FabricCommon
{

    public enum ApplicationModel
    {
        Web,
        Desktop,
        Cloud
    }

    public class Settings
    {
        internal Settings() { }
        public string this[string name]
        {
            get
            {
                switch (ApplicationEnvironment.ApplicationModel)
                {
                    case ApplicationModel.Cloud:
                        return RoleManager.GetConfigurationSetting(name);
                    case ApplicationModel.Desktop:
                        return ConfigurationManager.AppSettings[name];
                    case ApplicationModel.Web:
                        return WebConfigurationManager.AppSettings[name];
                    default:
                        throw new ApplicationException("Impossible");
                }
            }
        }
    }

    public class LocalStores
    {   
        string storesDir;

        internal LocalStores() 
        {
            if (ApplicationEnvironment.ApplicationModel != ApplicationModel.Cloud)
            {
                this.storesDir =
                  Path.Combine(Path.Combine(Path.GetTempPath(), "localstores"),
                               Path.GetRandomFileName());
            }
        }
       
       public string this[string name]
        { 
            get 
            {

                switch (ApplicationEnvironment.ApplicationModel)
                {
                    case ApplicationModel.Cloud:
                      return RoleManager.GetLocalResource(name).RootPath;
                    case ApplicationModel.Desktop: 
                    case ApplicationModel.Web:
                      string dirPath = Path.Combine(storesDir,name);
                      Directory.CreateDirectory(dirPath);
                      return dirPath;
                    default:
                        throw new ApplicationException("Impossible");
                }
            }
        }
    }
    
    static public class ApplicationEnvironment
    {   

        static public ApplicationModel ApplicationModel
        {
            get;
            private set;
        }

        static public LocalStores LocalStores
        {
            get;
            private set;
        }

        static public Settings Settings
        {
            get;
            private set;
        }

        static public void LogAlert(string msg) 
        {
            logger.LogAlert(msg); 
        }

        static public void LogError(string msg)
        {
            logger.LogError(msg);
        }

        static public void LogWarning(string msg) 
        {
            logger.LogWarning(msg); 
        }

        static public void LogInformation(string msg)
        {
            logger.LogInformation(msg); 
        }

        static public void LogVerbose(string msg) 
        { 
            logger.LogVerbose(msg);
        }

        #region Useful Overloads

        static private string FormatMessage(string format, Object[] args)
        {
            return String.Format(format, args);
        }

        static public void LogAlert(string format, params Object[] args)
        {
            LogAlert(FormatMessage(format, args));
        }

        static public void LogError(string format,params Object[] args)
        {
            LogError(FormatMessage(format, args));
        }

        static public void LogWarning(string format,params Object[] args)
        {
            LogWarning(FormatMessage(format, args));
        }

        static public void LogInformation(string format,params Object[] args)
        {
            LogInformation(FormatMessage(format, args));
        }

        static public void LogVerbose(string format,params Object[] args)
        {
            LogVerbose(FormatMessage(format, args));
        }

        #endregion

        #region Implementation

        private static LogPrimitives logger;

        internal abstract class LogPrimitives
        {
            public abstract void LogAlert(string msg);
            public abstract void LogError(string msg);
            public abstract void LogWarning(string msg);
            public abstract void LogInformation(string msg);
            public abstract void LogVerbose(string msg);
            
        }

        class RoleManagerLogger : LogPrimitives
        {
            public override void LogAlert(string msg)
            {
                RoleManager.WriteToLog("Critical", msg);
            }

            public override void LogError(string msg)
            {
                RoleManager.WriteToLog("Error", msg);
            }

            public override void LogWarning(string msg)
            {
                RoleManager.WriteToLog("Warning", msg);
            }

            public override void LogInformation(string msg)
            {
                RoleManager.WriteToLog("Information", msg);
            }

            public override void LogVerbose(string msg)
            {
                RoleManager.WriteToLog("Verbose", msg);
            }
        }

        class ConsoleLogger : LogPrimitives
        {
            static ConsoleColor defaultColor = System.Console.ForegroundColor;

            private static void WriteMessage(ConsoleColor color, string tag, string message)
            {
                System.Console.ForegroundColor = color;
                System.Console.WriteLine("{0} {1}: {2}",
                    System.DateTime.Now, tag, message);
            }

            public override void LogAlert(string msg)
            {
                WriteMessage(ConsoleColor.Magenta, "Alert", msg);
            }

            public override void LogError(string msg)
            {
                WriteMessage(ConsoleColor.Red, "Error", msg);
            }

            public override void LogWarning(string msg)
            {
                WriteMessage(ConsoleColor.Yellow, "Warning", msg);
            }

            public override void LogInformation(string msg)
            {
                WriteMessage(ConsoleColor.White, "Information", msg);
            }

            public override void LogVerbose(string msg)
            {
                WriteMessage(defaultColor, "Verbose", msg);
            }
        }

        class TraceLogger : LogPrimitives
        {   
            private static void WriteMessage(string tag, string message)
            {
                System.Diagnostics.Trace.WriteLine(String.Format("{0,02} {1,12}: {2}", 
                    System.Threading.Thread.CurrentThread.ManagedThreadId, 
                    tag, message));
            }

            public override void LogAlert(string msg)
            {
                WriteMessage("Alert", msg);
                System.Diagnostics.Debugger.Break();
            }

            public override void LogError(string msg)
            {
                WriteMessage("Error", msg);
            }

            public override void LogWarning(string msg)
            {
                WriteMessage("Warning", msg);
            }

            public override void LogInformation(string msg)
            {
                WriteMessage("Information", msg);
            }

            public override void LogVerbose(string msg)
            {
                WriteMessage("Verbose", msg);
            }
        }

        static ApplicationEnvironment()
        {            
            if (RoleManager.IsRoleManagerRunning)
            {
                ApplicationEnvironment.ApplicationModel = ApplicationModel.Cloud;
                ApplicationEnvironment.logger = new RoleManagerLogger();
            }
            else if (System.Web.HttpContext.Current != null)
            {
                ApplicationEnvironment.ApplicationModel = ApplicationModel.Web;
                ApplicationEnvironment.logger = new TraceLogger();
                System.Diagnostics.Trace.Listeners.Add(new System.Web.WebPageTraceListener());
            }
            else
            {
                ApplicationEnvironment.ApplicationModel = ApplicationModel.Desktop;
                ApplicationEnvironment.logger = new ConsoleLogger();
            }
            ApplicationEnvironment.Settings = new Settings();
            ApplicationEnvironment.LocalStores = new LocalStores();
        }
        #endregion
    }    
}
